﻿using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Serialization;

using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;

using Microsoft.Office.Server;
using Microsoft.Office.Server.UserProfiles;

using Behemoth.SharePoint;
using Behemoth.SharePoint.Logging;
using Behemoth.SharePoint.Web.YammerAPI;
using Behemoth.SharePoint.WebParts;

using Yammer;

namespace Behemoth.SharePoint.WebParts {

  [Guid("3c3b12f1-2899-4cd9-aec7-fbb391495dd7")]
  public class YammerWebPart : System.Web.UI.WebControls.WebParts.WebPart {

    public YammerWebPart() {
      this.ExportMode = WebPartExportMode.All;
    }

    #region Properties

    private YammerWebToolkit _yammerTools;
    public YammerWebToolkit YammerTools {
      get {
        if (_yammerTools == null) {
          if (!IsConfiguredWithRequiredProperties)
            throw new ArgumentException("Consumer Key or Secret are not set.");
          _yammerTools = new YammerWebToolkit(this.ConsumerKey, this.ConsumerSecret);
        }
        return _yammerTools;
      }
    }

    private const string EXCEPTION_MSG_AUTH = "Yammer returned error 401-Unauthorized. The most likely reason is that you have revoked authorization for this application to access Yammer. Please reauthorize using the link below.";

    protected ValidationSummary validation1;

    protected Panel panelSecurityCode;
    protected Label lblSecurityCode;
    protected TextBox textBoxSecurityCode;
    protected RequiredFieldValidator reqSecurityCode;
    protected Button buttonSecuritySubmit;
    protected LiteralControl litSpacer1;

    protected Panel panelPostMessage;
    protected Label lblPostMessage;
    protected TextBox textPostMessage;
    protected RequiredFieldValidator reqPostMessage;
    protected Button buttonPostMessage;
    protected LiteralControl litSpacer2;

    protected ErrorBag _errors = new ErrorBag();
    protected ULSTraceLogging _log = new ULSTraceLogging();
    private bool _accessResultSuccess = false;

    public bool IsConfiguredWithRequiredProperties {
      get { return !(string.IsNullOrEmpty(this.ConsumerKey) || string.IsNullOrEmpty(this.ConsumerSecret)); }
    }

    [WebBrowsable(true)]
    [Personalizable(PersonalizationScope.Shared)]
    [Category("Yammer Application Settings")]
    [WebDisplayName("Consumer Key")]
    [WebDescription("")]
    [Browsable(true)]
    [WebPartStorage(Storage.Shared)]
    [SPWebCategoryName("Yammer Application Settings")]
    [DisplayName("Consumer Key")]
    [Description("")]
    public string ConsumerKey {
      get {
        return _consumerKey;
      }
      set {
        _consumerKey = value;
      }
    }
    private string _consumerKey = string.Empty;

    [WebBrowsable(true)]
    [Personalizable(PersonalizationScope.Shared)]
    [Category("Yammer Application Settings")]
    [WebDisplayName("Consumer Secret")]
    [WebDescription("")]
    [Browsable(true)]
    [WebPartStorage(Storage.Shared)]
    [SPWebCategoryName("Yammer Application Settings")]
    [DisplayName("Consumer Secret")]
    [Description("")]
    public string ConsumerSecret {
      get {
        return _consumerSecret;
      }
      set {
        _consumerSecret = value;
      }
    }
    private string _consumerSecret = string.Empty;

    #endregion


    private void DoAuthTokenCheck() {
      if (YammerTools == null || this.DesignMode || !this.IsConfiguredWithRequiredProperties)
        return;
      YammerTools.DoAuthTokenCheck(_errors);
    }

    protected override void Render(HtmlTextWriter writer) {
      try {
        // output any errors, warnings, or info messages that may have been added.
        _errors.Render(writer);
        // if there was an error don't attempt to render the web part
        if (this._errors.HasErrors || this.DesignMode)
          return;
        else {
          if (!this.IsConfiguredWithRequiredProperties)
            WebPartUtilities.RenderToolPaneEditLink(writer, string.Empty, this);
          else {
            if (YammerTools.IsSettingsNull) {
              bool showInput = YammerTools.RenderAccessRequestLink(writer);
              panelSecurityCode.Visible = showInput;
            } else {
              //writer.Write("<div>Settings object is loaded.</ 
              YammerTools.WriteMessages(writer);
              panelPostMessage.Visible = true;
            }
            // renders child controls and stuff
            base.Render(writer);
          }
        } 
      } catch (Exception ex) {
        _log.Write(ex);
        writer.Write(string.Format("<div>Unexpected Exception while rendering web part. </p><div>Exception message: {0}</div><div> Stack Trace: {1}</div>", ex.Message, ex.StackTrace));
      }
    }

    protected override void OnPreRender(EventArgs e) {
      string thisFn = "OnPreRender";
      try {
        base.OnPreRender(e);
        if (this.DesignMode) {
          _errors.AddInfo("This web part does not render in Design Mode.");
          return;
        }
        if (!IsConfiguredWithRequiredProperties)
          return;
        DoAuthTokenCheck(); // does nothing if (!this.IsConfiguredWithRequiredProperties)
      } catch (Exception ex) {
        if (HandleAuthorizationException(ex, thisFn))
          return;
        this.HandleError(string.Format("Error in {0}()", thisFn), ex, true);
      }
    }

    protected override void OnInit(EventArgs e) {
      EnsureChildControls();
      base.OnInit(e);
    }

    protected override void OnLoad(EventArgs e) {
      string thisFn = "OnLoad";
      try {
        if (!IsConfiguredWithRequiredProperties)
          return;
        if (YammerTools.CleanCacheForNewPage(this.Page))
          this._errors.AddInfo("Authorization Cache was cleared. If you were in the process of authorizing this application on Yammer, you will need to clikc the link and begin again.");
        base.OnLoad(e);
      } catch (Exception ex) {
        this.HandleError(string.Format("Error in {0}()", thisFn), ex, true);
      }
    }

    protected override void CreateChildControls() {
      base.CreateChildControls();

      // validation summary
      validation1 = new ValidationSummary();
      validation1.ID = "ValidationSummary1";
      validation1.CssClass = "YammerWebParr";
      //validation1.ValidationGroup = "YammerWebPart_" + this.ID;
      validation1.EnableClientScript = true;
      validation1.Enabled = true;
      validation1.ShowMessageBox = true;
      validation1.ShowSummary = false;
      this.Controls.Add(validation1);

      // Post Message
      panelPostMessage = new Panel();
      panelPostMessage.Visible = false;
      panelPostMessage.CssClass = "ms-vb";
      panelPostMessage.ID = "PanelPostMessage";
      panelPostMessage.CssClass = "YammerWebPart_PostMessage";
      this.Controls.Add(panelPostMessage);

      lblPostMessage = new Label();
      lblPostMessage.Text = "Post a Message: ";
      lblPostMessage.ID = "LabelPostMessage";
      panelPostMessage.Controls.Add(lblPostMessage);

      textPostMessage = new TextBox();
      textPostMessage.ID = "InputPostMessage";
      textPostMessage.CssClass = "YammerWebParr";
      panelPostMessage.Controls.Add(textPostMessage);

      reqPostMessage = new RequiredFieldValidator();
      reqPostMessage.ID = "RequiredPostMessage";
      reqPostMessage.ControlToValidate = textPostMessage.ID;
      reqPostMessage.Text = "Please enter a message.";
      reqPostMessage.ErrorMessage = "Please enter a message.";
      reqPostMessage.EnableClientScript = validation1.EnableClientScript;
      reqPostMessage.Enabled = true;
      reqPostMessage.CssClass = "YammerWebParr";
      reqPostMessage.ValidationGroup = "YammerWebPart_PostMessage" + this.ID;
      panelPostMessage.Controls.Add(reqPostMessage);

      litSpacer2 = new LiteralControl("&nbsp;");
      litSpacer2.ID = "Spacer2";
      panelPostMessage.Controls.Add(litSpacer2);

      buttonPostMessage = new Button();
      buttonPostMessage.CausesValidation = true;
      buttonPostMessage.ValidationGroup = "YammerWebPart_" + this.ID;
      buttonPostMessage.ID = "ButtonPostMessage";
      buttonPostMessage.Text = "Authorize";
      buttonPostMessage.CssClass = "YammerWebParr";
      buttonPostMessage.Click += new EventHandler(buttonPostMessage_Click);
      panelPostMessage.Controls.Add(buttonPostMessage);


      // Security Code
      panelSecurityCode = new Panel();
      panelSecurityCode.Visible = false;
      panelSecurityCode.CssClass = "ms-vb";
      panelSecurityCode.ID = "InputPanel";
      panelSecurityCode.CssClass = "YammerWebParr";

      lblSecurityCode = new Label();
      lblSecurityCode.Text = "Enter Security Code: ";
      lblSecurityCode.ID = "LabelSecurityCode";
      panelSecurityCode.Controls.Add(lblSecurityCode);

      textBoxSecurityCode = new TextBox();
      textBoxSecurityCode.ID = "InputSecurityCode";
      textBoxSecurityCode.CssClass = "YammerWebParr";
      panelSecurityCode.Controls.Add(textBoxSecurityCode);

      reqSecurityCode = new RequiredFieldValidator();
      reqSecurityCode.ID = "RequiredSecurityCode";
      reqSecurityCode.ControlToValidate = textBoxSecurityCode.ID;
      reqSecurityCode.Text = "Please enter the 4 digit code to continue.";
      reqSecurityCode.ErrorMessage = "Please enter the 4 digit code to continue.";
      reqSecurityCode.EnableClientScript = validation1.EnableClientScript;
      reqSecurityCode.Enabled = true;
      reqSecurityCode.CssClass = "YammerWebParr";
      reqSecurityCode.ValidationGroup = "YammerWebPart_" + this.ID;
      panelSecurityCode.Controls.Add(reqSecurityCode);

      litSpacer1 = new LiteralControl("&nbsp;");
      litSpacer1.ID = "Spacer1";
      panelSecurityCode.Controls.Add(litSpacer1);

      buttonSecuritySubmit = new Button();
      buttonSecuritySubmit.CausesValidation = true;
      buttonSecuritySubmit.ValidationGroup = "YammerWebPart_" + this.ID;
      buttonSecuritySubmit.ID = "SecuritySubmit";
      buttonSecuritySubmit.Text = "Authorize";
      buttonSecuritySubmit.CssClass = "YammerWebParr";
      buttonSecuritySubmit.Click += new EventHandler(buttonSecuritySubmit_Click);
      panelSecurityCode.Controls.Add(buttonSecuritySubmit);

      this.Controls.Add(panelSecurityCode);
    }

    void buttonPostMessage_Click(object sender, EventArgs e) {
      try {
        YammerTools.PostMessage(this.textPostMessage.Text);
        _errors.AddInfo("Message posted.");
      } catch (Exception ex) {
        this.HandleError("Error in buttonPostMessage_Click()", ex, true);
      }
    }
    
    void buttonSecuritySubmit_Click(object sender, EventArgs e) {
      try {
        Page.Validate(); // TODO why is our client script not running here??
        // get the value from the textbox and save it to the Auth toolkit
        string code = this.textBoxSecurityCode.Text;
        if (YammerTools != null && YammerTools.Auth != null && !string.IsNullOrEmpty(code)) {
          YammerTools.Auth.CallbackToken = code;
        }
      } catch (Exception ex) {
        this.HandleError("Error in buttonSecuritySubmit_Click()", ex, true);
      }
    }

    private void HandleError(string msg, Exception ex, bool isError) {
      if (isError || ex != null) {
        _errors.AddError(msg);
        _errors.AddError(ex);
      } else {
        _errors.AddWarning(msg);
      }
      _log.Write(msg, isError ? TraceSeverity.Unexpected : TraceSeverity.WarningEvent);
      if (ex != null)
        _log.Write(ex);
    }

    /// <summary>
    /// Handles 401 Exceptions
    /// </summary>
    /// <param name="ex">The exception that is potentially an authorization exception.</param>
    /// <param name="callingFn">The name of the calling function to be used in error messages</param>
    /// <returns>true if the error was handled, false if you need to handle the exception in the caller</returns>
    private bool HandleAuthorizationException(Exception ex, string callingFn) {
      try {
        if (YammerWebToolkit.IsAuthorizationException(ex)) {
          this._errors.AddWarning(EXCEPTION_MSG_AUTH);
          YammerTools.ResetSettings(true);
          return true;
        }
      } catch (Exception ex2) {
        this.HandleError(string.Format("Error in {0}() - CatchAuthException", callingFn), ex2, true);
      }
      return false;
    }




  } // class
} // namespace
